`timescale 1ns/1ps
`default_nettype none
//文件名：rtl/cpu_top.v
//作用：CPU 顶层模块
module cpu_top #(
    parameter IMEM_DEPTH = 1024*256   // 指令存储深度（按字）
)(
    input  wire clk,   // 时钟：所有时序单元在上升沿工作
    input  wire rstn,   // 同步复位（低有效）：拉低一个或多个时钟上升沿生效

    // ---- TinyBus Master 接口 ----
    output wire        m_req_valid,
    output wire [31:0] m_req_addr,
    output wire [31:0] m_req_wdata,
    output wire [3:0]  m_req_be,
    output wire        m_req_we,
    input  wire        m_req_ready,
    input  wire        m_rsp_valid,
    input  wire [31:0] m_rsp_rdata,
    input  wire        m_rsp_err,
    // 仅用于 TB 抓取
    output wire [31:0] mon_addr,
    output wire [31:0] mon_wdata,
    output wire [3:0]  mon_we

);

    // ================= WB（先声明，便于前面模块引用） =================
    wire [31:0] wb_wdata;
    wire [4:0]  wb_rd;
    wire        wb_regwrite;
    // 这些信号会在后面 MEM/WB 级产生，但这里先前置声明，供 wb_wdata 组合使用
    wire [31:0] wb_alu_y, wb_rdata, wb_pc4;
    wire        wb_memtoreg, wb_jal, wb_jalr;

    // CSR 写回通路（旧值）
    wire        wb_is_csr;
    wire [31:0] wb_csr_rdata;

    // =========================================================================
    // IF 取指阶段
    //   - pc 仅做：复位到 0，每拍 +4
    //   - imem 按字对齐读取指令（addr[31:2] 作为字地址）
    //   - if_id_reg 打拍 pc 与 instr，进入 ID 阶段
    // =========================================================================
    wire        hz_stall;                 // hazard: 冻结 IF/ID、PC
    wire        hz_flush;                 // hazard: 向 ID/EX 注入气泡

    wire        pc_src;                   // EX: 是否重定向 PC
    wire [31:0] pc_target;                // EX: 重定向目标地址（J/JR/BR）
    wire        pc_en = ~hz_stall;        // 冻结 PC（load-use）

    wire [31:0] if_pc;                    // 当前 PC
    wire [31:0] if_instr;                 // 取回指令

    pc u_pc(
        .clk      (clk),
        .rstn     (rstn),
        .en       (pc_en),
        .pc_src   (pc_src),
        .pc_target(pc_target),
        .pc_q     (if_pc)
    );

    // 说明：imem 内部不做 $readmemh，便于 tb 层统一加载（层次路径：dut.u_imem.mem）
    imem #(
        .DEPTH_WORDS(IMEM_DEPTH)
    ) u_imem (
        .addr (if_pc),
        .instr(if_instr)
    );

    // =========================================================================
    // IF/ID —— 打拍到译码级，支持 en / flush
    // =========================================================================
    wire        ifid_en    = ~hz_stall;   // 冻结 IF/ID
    wire        ifid_flush;               // 跳/分支命中 冲刷
    wire [31:0] id_pc;
    wire [31:0] id_instr;
    
    if_id_reg u_ifid(
        .clk     (clk),
        .rstn    (rstn),
        .en      (ifid_en),
        .flush   (ifid_flush),
        .if_pc   (if_pc),
        .if_instr(if_instr),
        .id_pc   (id_pc),
        .id_instr(id_instr)
    );

    // =========================================================================
    // ID 译码/读寄存器阶段
    //   - controller：根据 opcode/funct3/funct7 组合译码出：regwrite / alusrc / alu_ctrl
    //   - regfile   ：组合读 rs1, rs2；同步写（x0 恒 0）
    //   - imm_gen   ：生成 I 型有符号扩展立即数
    //   - id_ex_reg ：将 rs1、rs2、imm 及控制信号打拍到 EX
    // =========================================================================
    // RISC-V 位段（供直连与注释理解；控制器内部也会拆解）
    wire [4:0] rs1 = id_instr[19:15];
    wire [4:0] rs2 = id_instr[24:20];
    wire [4:0] rd  = id_instr[11:7];
    wire [4:0] id_zimm5 = id_instr[19:15];  // CSR *I 的 zimm[4:0]

    // controller：当前仅输出三条信号
    wire        c_regwrite;  // 本指令最终是否需要写回寄存器堆
    wire        c_alusrc_b;    // 1=ALU 的 B 源取 imm（I 型），0=取 rs2（R 型）
    wire [3:0]  c_alu_ctrl;  // 0000=ADD，0001=SUB（与 alu.v 对齐）
    wire        c_memread;
    wire        c_memwrite;
    wire        c_memtoreg;
    wire        c_jal;
    wire        c_branch;
    wire        c_jalr;
    wire [2:0]  c_branch_type;        // 000=BEQ 001=BNE 010=BLT 011=BGE 100=BLTU 101=BGEU
    wire [1:0]  c_alu_src_a_sel;      // 00=rs1 01=pc 10=zero
    wire [1:0]  c_load_size;          // 00=byte 01=half 10=word
    wire        c_load_unsigned;      // 1=无符号（LBU/LHU）
    wire [1:0]  c_store_size;         // 00=SB 01=SH 10=SW
    wire        c_use_imm_u;          // LUI/AUIPC 使用 U 型立即数

    // CSR/Trap
    wire        c_is_csr;
    wire [2:0]  c_csr_funct3;
    wire [11:0] c_csr_addr;
    wire        c_is_ecall;
    wire        c_is_mret;
    // wire        c_fencei;

    controller u_ctrl(
        .instr    (id_instr),
        .regwrite (c_regwrite),
        .alusrc_b (c_alusrc_b),
        .alu_ctrl (c_alu_ctrl),
        .memread(c_memread), 
        .memwrite(c_memwrite), 
        .memtoreg(c_memtoreg),
        .jal(c_jal),
        .branch(c_branch),                     // ★ BEQ 标志
        .jalr(c_jalr),
        .branch_type    (c_branch_type),
        .alu_src_a_sel  (c_alu_src_a_sel),
        .load_size      (c_load_size),
        .load_unsigned  (c_load_unsigned),
        .store_size     (c_store_size),
        .use_imm_u      (c_use_imm_u),

        .is_csr         (c_is_csr),
        .csr_funct3     (c_csr_funct3),
        .csr_addr       (c_csr_addr),
        .is_ecall       (c_is_ecall),
        .is_mret        (c_is_mret)
    );

    // 寄存器堆：组合读（rdata1/rdata2），同步写（在 WB 阶段完成）
    wire [31:0] rdata1;
    wire [31:0] rdata2;

    assign wb_wdata =
        (wb_jal | wb_jalr) ? wb_pc4 :
        (wb_memtoreg)      ? wb_rdata :
        (wb_is_csr)        ? wb_csr_rdata :
                             wb_alu_y;

    regfile u_rf(
        .clk   (clk),
        .rstn  (rstn),
        .we    (wb_regwrite),   // 来自 MEM/WB 的写回使能
        .rs1   (rs1),
        .rs2   (rs2),
        .rd    (wb_rd),         // 回写目的寄存器
        .wdata (wb_wdata),      // 回写数据（最小版：恒为 ALU 结果）
        .rdata1(rdata1),
        .rdata2(rdata2)
    );

    // 立即数生成：仅 I 型用到（ADDI）
    wire [31:0] imm_i, imm_s, imm_j, imm_b, imm_u;
    imm_gen u_imm(
        .instr(id_instr),
        .imm_i(imm_i), 
        .imm_s(imm_s),
        .imm_j(imm_j), 
        .imm_b(imm_b),
        .imm_u(imm_u)
    );
    wire [31:0] id_imm_is  = c_memwrite ? imm_s : imm_i;      // Stores 用 S，其它 I
    wire [31:0] id_imm_mux = c_jal     ? imm_j :
                              c_branch  ? imm_b :
                              c_use_imm_u ? imm_u : 
                              id_imm_is;
    wire [31:0] id_pc4     = id_pc + 32'd4;             // 计算 pc+4（JAL 写回 link 值用）

    // ===== Hazard Unit =====

    hazard_unit u_hz(
        .ex_memread(ex_memread),   // EX 阶段：由 ID/EX 打拍而来
        .id_rs1    (rs1),          // ID 阶段：本拍解码的源寄存器
        .id_rs2    (rs2),
        .ex_rd    (ex_rd),
        .stall     (hz_stall),
        .flush     (hz_flush)
    );

    // ID/EX 级间寄存器：把 ID 阶段的数据与控制信号打拍给 EX
    wire [31:0] ex_pc, ex_pc4;   // ★ 新增 JAL
    wire [31:0] ex_rdata1;
    wire [31:0] ex_rdata2;
    wire [31:0] ex_imm;
    wire [4:0]  ex_rs1, ex_rs2, ex_rd; // ★ 新增 增加 exrs1 和 exrs2解决数据冒险
    wire        ex_regwrite;
    wire        ex_alusrc_b;
    wire [3:0]  ex_alu_ctrl;
    wire        idex_flush;            // ★ 新增

    //为mem存阶段增加
    wire        ex_memread, ex_memwrite, ex_memtoreg;
    wire        ex_jal;  //★ 新增 JAL
    wire        ex_branch;  //★ 新增 BEQ
    wire        ex_jalr;
    wire [1:0]  ex_alu_src_a_sel;     // 00=rs1 01=pc 10=zero
    wire [2:0]  ex_branch_type;       // BEQ/BNE/...
    wire [1:0]  ex_load_size;
    wire        ex_load_unsigned;
    wire [1:0]  ex_store_size;

    // CSR/Trap
    wire        ex_is_csr;
    wire [2:0]  ex_csr_funct3;
    wire [11:0] ex_csr_addr;
    wire        ex_is_ecall, ex_is_mret;
    wire [4:0]  ex_zimm5;

    wire        trap_taken;          // EX Trap

    id_ex_reg u_idex(
        .clk        (clk),
        .rstn       (rstn),
        .flush      (idex_flush),       // ★ 新增：注入 NOP

        .id_pc      (id_pc),             // ★ 新增JAL
        .id_pc4     (id_pc4),             // ★ 新增JAL
        .id_rdata1  (rdata1),
        .id_rdata2  (rdata2),
        .id_imm     (id_imm_mux),       // ★ JAL 时把 J 立即数送进来
        .id_rs1     (rs1),                 // ★ 新增 解决数据冒险
        .id_rs2     (rs2),                 // ★ 新增 解决数据冒险
        .id_rd      (rd),

        .id_regwrite(c_regwrite),
        .id_alusrc_b  (c_alusrc_b),
        .id_alu_ctrl(c_alu_ctrl),
        .id_memread(c_memread),           // ★ 新增 为访存
        .id_memwrite(c_memwrite),         // ★ 新增 为访存
        .id_memtoreg(c_memtoreg),         // ★ 新增 为访存
        .id_jal     (c_jal),              // ★ 新增 JAL
        .id_branch  (c_branch),             // ★ 新增 BEQ  打拍到 EX
        .id_jalr    (c_jalr),             // ★ 新增 JALR

        .id_alu_src_a_sel(c_alu_src_a_sel), 
        .id_branch_type(c_branch_type),
        .id_load_size(c_load_size), 
        .id_load_unsigned(c_load_unsigned), 
        .id_store_size(c_store_size),

        .id_is_csr        (c_is_csr),
        .id_csr_funct3    (c_csr_funct3),
        .id_csr_addr      (c_csr_addr),
        .id_is_ecall      (c_is_ecall),
        .id_is_mret       (c_is_mret),
        .id_zimm5         (id_zimm5),

        .ex_pc      (ex_pc),              // ★ 新增JAL
        .ex_pc4     (ex_pc4),             // ★ 新增JAL
        .ex_rdata1  (ex_rdata1),
        .ex_rdata2  (ex_rdata2),
        .ex_imm     (ex_imm),
        .ex_rs1     (ex_rs1),           // ★ 新增 解决数据冒险
        .ex_rs2     (ex_rs2),           // ★ 新增 解决数据冒险
        .ex_rd      (ex_rd),

        .ex_regwrite(ex_regwrite),
        .ex_alusrc_b  (ex_alusrc_b),
        .ex_alu_ctrl(ex_alu_ctrl),
        .ex_memread(ex_memread),          // ★ 新增 为访存
        .ex_memwrite(ex_memwrite),        // ★ 新增 为访存
        .ex_memtoreg(ex_memtoreg),         // ★ 新增 为访存
        .ex_jal(ex_jal),                   // ★ 新增 JAL
        .ex_branch(ex_branch),              // ★ 新增 BEQ
        .ex_jalr(ex_jalr),
        .ex_alu_src_a_sel(ex_alu_src_a_sel),
        .ex_branch_type (ex_branch_type),
        .ex_load_size   (ex_load_size),
        .ex_load_unsigned(ex_load_unsigned),
        .ex_store_size  (ex_store_size),

        .ex_is_csr        (ex_is_csr),
        .ex_csr_funct3    (ex_csr_funct3),
        .ex_csr_addr      (ex_csr_addr),
        .ex_is_ecall      (ex_is_ecall),
        .ex_is_mret       (ex_is_mret),
        .ex_zimm5         (ex_zimm5)
    );


    // =========================================================================
    // EX 执行阶段
    //   - 选择 ALU 的 B 源：I 型 -> imm；R 型 -> rs2
    //   - ALU 根据 alu_ctrl 执行加/减；结果进入 EX/MEM
    // =========================================================================

    // CSR / Trap（最小）
    wire [31:0] csr_rdata;
    wire [31:0] trap_target;


    csrfile u_csr (
        .clk        (clk),
        .rstn       (rstn),
        .csr_en     (ex_is_csr),
        .csr_funct3 (ex_csr_funct3),
        .csr_addr   (ex_csr_addr),
        .rs1_val    (alu_a_pre),     // rs1（已前递）作为源
        .zimm       (ex_zimm5),  //ex_zimm5  ex_rs1[4:0] // 对 *I 变体，rs1 字段其实是 zimm[4:0]；也可从指令取
        .csr_rdata  (csr_rdata),
        .ecall      (ex_is_ecall),
        .mret       (ex_is_mret),
        // ★ 新增：EX 阶段对齐异常
        .exc_valid  (exc_valid_ex),
        .exc_cause  (exc_cause_ex),
        .exc_tval   (exc_tval_ex),

        .trap_taken (trap_taken),
        .trap_target(trap_target),
        .cur_pc     (ex_pc)
    );

    // 前递控制：比较 EX 源 vs EX/MEM & MEM/WB 的写回目的
    wire [1:0] fwd_a_sel, fwd_b_sel;
    forwarding_unit u_fwd(
        .ex_rs1(ex_rs1), 
        .ex_rs2(ex_rs2),
        .mem_regwrite(mem_regwrite), 
        .mem_rd(mem_rd),
        .wb_regwrite(wb_regwrite),   
        .wb_rd(wb_rd),
        .fwd_a_sel(fwd_a_sel), 
        .fwd_b_sel(fwd_b_sel)
    );

    // 前递源：EX/MEM 走 ALU 结果，MEM/WB 走“最终写回数据”（含 LOAD/JAL/JALR）
    wire [31:0] fwd_from_mem = mem_alu_y;
    wire [31:0] fwd_from_wb  = wb_wdata;

    // EX 阶段 rs1/rs2 前递后的值
    reg  [31:0] alu_a_pre, rdata2_fwd;
    always @* begin
        // rs1
        case (fwd_a_sel)
          2'b10:   alu_a_pre  = fwd_from_mem;   // EX/MEM
          2'b01:   alu_a_pre  = fwd_from_wb;    // MEM/WB
          default: alu_a_pre  = ex_rdata1;      // 原值
        endcase
        // rs2
        case (fwd_b_sel)
          2'b10:   rdata2_fwd = fwd_from_mem;   // EX/MEM
          2'b01:   rdata2_fwd = fwd_from_wb;    // MEM/WB
          default: rdata2_fwd = ex_rdata2;      // 原值
        endcase
    end
                                                               
    // --- ALU A/B 源多路 ---
    wire [31:0] ex_a_sel =
        (ex_alu_src_a_sel==2'b01) ? ex_pc  :
        (ex_alu_src_a_sel==2'b10) ? 32'b0  :
                                    alu_a_pre;      // 默认 rs1
    wire [31:0] ex_b_sel = ex_alusrc_b ? ex_imm : rdata2_fwd;

    // --- ALU ---
    wire [31:0] ex_alu_y;
    alu u_alu(
        .a        (ex_a_sel),
        .b        (ex_b_sel),
        .alu_ctrl (ex_alu_ctrl),  
        .y        (ex_alu_y)
    );

    // ---- 地址对齐检测（EX 阶段）----
    wire ex_misal_load  =
        ex_memread  && ( (ex_load_size  == 2'b10 && ex_alu_y[1:0] != 2'b00) ||   // LW 要 4B 对齐
                         (ex_load_size  == 2'b01 && ex_alu_y[0]   != 1'b0) );     // LH 要 2B 对齐
    wire ex_misal_store =
        ex_memwrite && ( (ex_store_size == 2'b10 && ex_alu_y[1:0] != 2'b00) ||
                         (ex_store_size == 2'b01 && ex_alu_y[0]   != 1'b0) );

    wire exc_valid_ex = ex_misal_load | ex_misal_store;
    wire [31:0] exc_cause_ex = ex_misal_load ? 32'd4 : 32'd6;   // 4=load-misal, 6=store-misal
    wire [31:0] exc_tval_ex  = ex_alu_y;

    // 发生异常时，禁止这条指令产生副作用（不写内存/不写回/不走 MEM->WB）
    wire ex_memread_ok   = ex_memread   & ~exc_valid_ex;
    wire ex_memwrite_ok  = ex_memwrite  & ~exc_valid_ex;
    wire ex_memtoreg_ok  = ex_memtoreg  & ~exc_valid_ex;
    wire ex_regwrite_ok  = ex_regwrite  & ~exc_valid_ex;


    // --- 分支比较：eq/lt(有符号)/ltu(无符号) ---
    wire eq  = (alu_a_pre == rdata2_fwd);
    wire lts = ($signed(alu_a_pre) < $signed(rdata2_fwd));
    wire ltu = (alu_a_pre < rdata2_fwd);

    wire ex_br_taken =
        ex_branch && (
          (ex_branch_type==3'b000) ?  eq  :  // BEQ
          (ex_branch_type==3'b001) ? ~eq  :  // BNE
          (ex_branch_type==3'b010) ?  lts :  // BLT
          (ex_branch_type==3'b011) ? ~lts :  // BGE
          (ex_branch_type==3'b100) ?  ltu :  // BLTU
          (ex_branch_type==3'b101) ? ~ltu :  // BGEU
                                      1'b0 );

    // --- 跳转/分支 目标地址 ---
    wire [31:0] jal_target  = ex_pc + ex_imm;              // JAL
    wire [31:0] br_target   = ex_pc + ex_imm;              // Branch
    wire [31:0] jalr_sum    = alu_a_pre + ex_imm;          // rs1 + imm_i
    wire [31:0] jalr_target = {jalr_sum[31:1], 1'b0};     // ★ 4 字节对齐（方案 B）

    // --- PC 重定向 & 冲刷 ---
    assign pc_src     = ex_jal | ex_jalr | ex_br_taken | trap_taken;
    assign pc_target  = trap_taken ? trap_target :
                        ex_jal  ? jal_target  :
                        ex_jalr ? jalr_target :
                                   br_target;

    assign ifid_flush = ex_jal | ex_jalr | ex_br_taken | trap_taken ;         // 冲刷 IF/ID
    assign idex_flush = hz_flush | ex_jal | ex_jalr | ex_br_taken | trap_taken ; // 插泡或控制冲刷


    // EX/MEM 级间寄存器：把 ALU 结果与写回元信息打拍给 MEM
    wire [31:0] mem_alu_y,mem_wdata, mem_pc4;  // ★为访存指令增加mem_wdata
    wire [4:0]  mem_rd;
    wire        mem_regwrite;

    //为访存指令增加
    wire        mem_memread, mem_memwrite, mem_memtoreg;
    wire        mem_jal , mem_jalr;
    wire [1:0]  mem_load_size;
    wire        mem_load_unsigned;
    wire [1:0]  mem_store_size;

    // CSR 旧值
    wire        mem_is_csr;
    wire [31:0] mem_csr_rdata;

    ex_mem_reg u_exmem(
        .clk        (clk),
        .rstn       (rstn),
        .ex_alu_y   (ex_alu_y), 
        .ex_wdata   (rdata2_fwd),      // ★ SW 的写数据使用前递后的 rs2
        .ex_pc4     (ex_pc4),            // ★ 新增
        .ex_rd      (ex_rd),
        .ex_regwrite(ex_regwrite_ok),
        .ex_memread(ex_memread_ok),        // ★为访存指令增加
        .ex_memwrite(ex_memwrite_ok),      // ★为访存指令增加
        .ex_memtoreg(ex_memtoreg_ok),      // ★为访存指令增加
        .ex_jal     (ex_jal),            // ★ 新增
        .ex_jalr     (ex_jalr),

        .ex_load_size   (ex_load_size),
        .ex_load_unsigned(ex_load_unsigned),
        .ex_store_size  (ex_store_size),

        .ex_is_csr      (ex_is_csr),
        .ex_csr_rdata   (csr_rdata),

        .mem_alu_y  (mem_alu_y),
        .mem_wdata(mem_wdata),
        .mem_pc4    (mem_pc4),          // ★ 新增
        .mem_rd     (mem_rd),
        .mem_regwrite(mem_regwrite),
        .mem_memread(mem_memread),      // ★为访存指令增加
        .mem_memwrite(mem_memwrite),    // ★为访存指令增加
        .mem_memtoreg(mem_memtoreg),     // ★为访存指令增加
        .mem_jal     (mem_jal),           // ★ 新增
        .mem_jalr     (mem_jalr),

        .mem_load_size  (mem_load_size),
        .mem_load_unsigned(mem_load_unsigned),
        .mem_store_size (mem_store_size),

        .mem_is_csr     (mem_is_csr),
        .mem_csr_rdata  (mem_csr_rdata)
    );

    // =========================================================================
    // MEM —— 访存级：DMEM 接口 + LOAD 扩展 + STORE 字节使能
    // =========================================================================
    wire [1:0]  mem_offs = mem_alu_y[1:0];

    // 生成 DMEM 写使能（SB/SH/SW）
    reg  [3:0]  mem_byte_we;
    always @* begin
        mem_byte_we = 4'b0000;
        if (mem_memwrite) begin
            case (mem_store_size)
                2'b00: mem_byte_we = 4'b0001 << mem_offs;                     // SB
                2'b01: mem_byte_we = (mem_offs[1]==1'b0) ? 4'b0011 : 4'b1100; // SH
                2'b10: mem_byte_we = 4'b1111;                                 // SW
                default: mem_byte_we = 4'b0000;
            endcase
        end
    end

    // ★★ 关键改动：把写数据按 addr[1:0] 放到正确的 lane（CPU 侧对齐）
    reg [31:0] mem_wdata_aligned;
    always @* begin
        mem_wdata_aligned = 32'h0;
        if (mem_memwrite) begin
            case (mem_store_size)
                2'b00: begin // SB
                    mem_wdata_aligned = {24'h0, mem_wdata[7:0]} << (8*mem_offs);
                end
                2'b01: begin // SH（此时 mem_offs[0]==0，不跨字）
                    mem_wdata_aligned = {16'h0, mem_wdata[15:0]} << (8*mem_offs);
                end
                2'b10: begin // SW（此时 mem_offs==0）
                    mem_wdata_aligned = mem_wdata;
                end
                default: mem_wdata_aligned = 32'h0;
            endcase
        end
    end


    // // 数据存储器（同步读写）
    // wire [31:0] mem_rdata_word;
    // dmem #(.DEPTH_BYTES(64*1024)) 
    // u_dmem(
    //     .clk(clk),
    //     .rstn   (rstn),
    //     .addr   (mem_alu_y),
    //     .wdata  (mem_wdata_aligned),   // ★ 用对齐后的数据
    //     .byte_we(mem_byte_we),
    //     .rdata  (mem_rdata_word)     // 返回整字
    // );
    // ===== 用 TinyBus Master 发起访存请求 =====
    assign m_req_addr   = mem_alu_y;           // 字节地址
    assign m_req_wdata  = mem_wdata_aligned;   // 已按 lane 对齐
    assign m_req_be     = mem_byte_we;         // 字节写使能
    assign m_req_we     = mem_memwrite;        // 写=1 / 读=0
    assign m_req_valid  = mem_memwrite | mem_memread;

    // 可选：给 TB 的监视端口（若你在端口里加了）
    assign mon_addr  = m_req_addr;
    assign mon_wdata = m_req_wdata;
    assign mon_we    = (m_req_valid && m_req_we) ? m_req_be : 4'b0000;

    // 对于当前设计：从机均为零等待（ready=1），因此不做 MEM 级气泡/暂停。
    // 若未来有慢设备：可用 mem_wait = tb_m_valid & ~tb_m_ready 去冻结 PC/IFID/流水线。
    wire [31:0] mem_rdata_word;
    assign mem_rdata_word = m_rsp_rdata;  // 用总线回读替代原 dmem.rdata

    // ---------- A) 异步读：与原来一致 ----------
    wire [7:0]  ld_byte = (mem_offs==2'd0)? mem_rdata_word[7:0]  :
                        (mem_offs==2'd1)? mem_rdata_word[15:8] :
                        (mem_offs==2'd2)? mem_rdata_word[23:16]: mem_rdata_word[31:24];
    wire [15:0] ld_half = (mem_offs[1]==1'b0) ? mem_rdata_word[15:0] : mem_rdata_word[31:16];

    wire [31:0] mem_ldext =
        (mem_load_size==2'b00) ? (mem_load_unsigned ? {24'b0, ld_byte} : {{24{ld_byte[7]}}, ld_byte}) :
        (mem_load_size==2'b01) ? (mem_load_unsigned ? {16'b0, ld_half} : {{16{ld_half[15]}}, ld_half}) :
                                mem_rdata_word;

    // ---------- 直接送入 MEM/WB ----------
    mem_wb_reg u_memwb(
        .clk         (clk),
        .rstn        (rstn),
        .mem_alu_y   (mem_alu_y),
        .mem_rdata   (mem_ldext),
        .mem_pc4     (mem_pc4),
        .mem_rd      (mem_rd),
        .mem_regwrite(mem_regwrite),
        .mem_memtoreg(mem_memtoreg),
        .mem_jal     (mem_jal),
        .mem_jalr    (mem_jalr),

        .mem_is_csr   (mem_is_csr),
        .mem_csr_rdata(mem_csr_rdata),

        .wb_alu_y    (wb_alu_y),
        .wb_rdata    (wb_rdata),
        .wb_pc4      (wb_pc4),
        .wb_rd       (wb_rd),
        .wb_regwrite (wb_regwrite),
        .wb_memtoreg (wb_memtoreg),
        .wb_jal      (wb_jal),
        .wb_jalr     (wb_jalr),

        .wb_is_csr    (wb_is_csr),
        .wb_csr_rdata (wb_csr_rdata)
    );

    // =========================================================================
    // WB 回写阶段
    // =========================================================================
    
    //代码写在寄存器那里

    // ---- DEBUG: 只打印第一次遇到的 AUIPC ----
    // reg dbg_seen_auipc = 1'b0;
    // always @(posedge clk) if (rstn && !dbg_seen_auipc) begin
    // // AUIPC 的判定条件：A 源选 PC，B 源选立即数，ALU 做 ADD
    // if (ex_alu_src_a_sel==2'b01 && ex_alusrc_b==1'b1 && ex_alu_ctrl==4'b0000) begin
    //     dbg_seen_auipc <= 1'b1;
    //     $display("[%0t] AUIPC: ex_pc=0x%08x  imm_u=0x%08x  y=0x%08x",
    //             $time, ex_pc, ex_imm, ex_alu_y);
    // end
    // end

    // always @(posedge clk) if (rstn && ex_jalr) begin
    //     $display("[%0t] JALR: rs1=0x%08x imm=0x%08x sum=0x%08x -> target=0x%08x",
    //             $time, alu_a_pre, ex_imm, (alu_a_pre+ex_imm), jalr_target);
    // end

    // 当 EX 阶段是 OP-IMM 且 rd==1 时打印关键控制与操作数
    // always @(posedge clk) begin
    //     if (rstn && ex_regwrite && (ex_rd==5'd1) && (ex_alusrc_b==1'b1)) begin
    //         $display("[%0t] EX: ADDI to x1  a_sel=%b b_sel=%b alu_ctrl=%b  a=0x%08x imm=0x%08x  alu_y=0x%08x",
    //         $time, ex_alu_src_a_sel, ex_alusrc_b, ex_alu_ctrl, alu_a_pre, ex_imm, ex_alu_y);
    //     end
    // end

    // always @(posedge clk) if (rstn && wb_regwrite) begin
    //     $display("[%0t] WB: rd=%0d WD=0x%08x  src=%s",
    //         $time, wb_rd, wb_wdata,
    //         (wb_jal|wb_jalr) ? "PC+4" : (wb_memtoreg ? "MEM" : "ALU"));
    // end




endmodule